# -*- coding: utf-8 -*-

from django.utils.datastructures import MultiValueDict
from werkzeug.datastructures import ImmutableMultiDict as wrkz_ImmutableMultiDict
from functools import partial

from django import forms as djforms
from django.forms.fields import CharField, Field
from django.forms.widgets import Input as InputWidget
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _

import jinja2, html5lib
from html5lib.sanitizer import HTMLSanitizer
from html5lib.treebuilders import getTreeBuilder

from lenta.code.backends.working.models import MAXIMUM_TAG_LENGTH


class VideoHTMLSanitizer(HTMLSanitizer):
    allowed_elements = HTMLSanitizer.allowed_elements + ['iframe', 'object']
    allowed_elements.sort()
    allowed_attributes = HTMLSanitizer.allowed_attributes + ['frameborder', 'allowfullscreen']
    allowed_attributes.sort()

html_sanitizer = html5lib.HTMLParser(tokenizer=VideoHTMLSanitizer, tree=getTreeBuilder("dom"))
html_serializer = partial(html5lib.serialize, tree="dom", format="xhtml")


def _POST(post):
    """ адаптер, который преобразует werkzeug.datastructures.ImmutableMultiDict
        в django.utils.datastructures.MultiValueDict
    """
    data = {}
    for key in post.keys():
        data[key] = post.getlist(key)    
    return MultiValueDict(data)         


class DhForm(djforms.Form):
    def __init__(self, data=None, **kw):
        if isinstance(data, wrkz_ImmutableMultiDict):
            data = _POST(data)
        kw['error_class'] = list    
        super(DhForm, self).__init__(data, **kw)
        
    def full_clean(self):
        """
        Overiding method of base class because I'm sick of Django's ErrorDict and ErrorList.
        """
        self._errors = dict()
        if not self.is_bound: # Stop further processing.
            return
        self.cleaned_data = {}
        # If the form is permitted to be empty, and none of the form data has
        # changed from the initial data, short circuit any validation.
        if self.empty_permitted and not self.has_changed():
            return
        self._clean_fields()
        self._clean_form()
        self._post_clean()
        if self._errors:
            del self.cleaned_data
            
    def htmlize(self):
        """ """
        data = self.data
        return dict((n, fld.widget._format_value(data.get(n)) if hasattr(fld.widget, '_format_value') else data.get(n))
                        for n, fld in self.fields.iteritems())
        

class CSVWidget(InputWidget):
    """ """
    def _format_value(self, value):
        """ """
        return ", ".join(value)

class CSVCharField(Field):
    """ """
    widget = CSVWidget
    
    def to_python(self, value):
        """ """
        value = super(CSVCharField, self).to_python(value)
        return list(set(item.strip() for item in value.split(',') if item.strip())) if value else []
    

class CharFieldEscapeHtml(CharField):
    """ """
    def clean(self, value):
        """ """
        value = super(CharFieldEscapeHtml, self).clean(value)
        return unicode(jinja2.filters.escape(value))
        

class CharFieldSanitizeHtml(CharField):
    """ """
    def clean(self, value):
        """ """
        value = super(CharFieldSanitizeHtml, self).clean(value)
        return html_serializer(html_sanitizer.parse(value).getElementsByTagName('body')[0])[6:-7]
    
    
class TagsField(CSVCharField):
    """ 
    Form field for comma separated tags with additional clean logic
    """
    default_error_messages = {
        'max_length': _(u'Tag length is limited to %s symbols' % MAXIMUM_TAG_LENGTH)
    }
    
    def validate(self, value):
        """ """
        super(TagsField, self).validate(value)
        for tag in value:
            if len(tag) > MAXIMUM_TAG_LENGTH:
                raise ValidationError(self.error_messages['max_length'])
            

class TagNameField(CharFieldEscapeHtml):
    """ """
    default_error_messages = {
        'max_length': _(u'Tag length is limited to %s symbols' % MAXIMUM_TAG_LENGTH)
    }
    
    def validate(self, value):
        """ """
        super(TagNameField, self).validate(value)
        if len(value) > MAXIMUM_TAG_LENGTH:
            raise ValidationError(self.error_messages['max_length'])       